 
  

 






<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do;jsessionid=4FCCB481C702D708A7360133D128E359?Id=209 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:01 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
<head>
 <title>
  Java Practices -> Validation belongs in a Model Object
 </title>
 <link rel="stylesheet" type="text/css" href="../stylesheet8.css" media="all">
 
 <link rel="shortcut icon" href='../images/favicon.ico' type="image/vnd.microsoft.icon">
 <meta name="description" content="Concise presentations of java programming practices, tasks, and conventions, amply illustrated with syntax highlighted code examples.">
 
 <meta name='keywords' content='java,java programming,java practices,java idiom,java style,java design patterns,java coding conventions,'>
 
 
</head>
 
<body>


<div class='menu-bar'>
 
  <a href='../home/HomeAction.html' title='Table of Contents'>Home</a> |
  <a href='../vote/VoteSummaryAction-2.html' title='View Poll Results'>Poll</a> |
   
  <A href='../feedback/FeedbackAction451f-2.html?Operation=Show' title='Send Your Feedback'>Wiki</a> |
  <b><a href='../source/SourceAction-2.html' title='Grab Source Code'>Source Code</a></b><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |

  <a href='http://www.web4j.com/Java_Web_Application_Framework_Overview.jsp?From=1' title='Free Download - Java Web Application Framework'><b>WEB4J</b></a> |
  
  <a href='http://www.date4j.net/' title='Replacement for java.util.Date'><b>DATE4J</b></a> |

   <a href='../references/ReferencesAction-2.html' title='References'>Links</a>
   
  <form action='http://www.javapractices.com/search/SearchAction.do' method='get' class='search-form'>
   <input type='text' name='SearchTerms' value="" size=12 maxlength=50 class='search'>
   <input type='submit' value="Search">
  </form>
 
</div>

<P>



  

 






<p class="display-messages">

 

 

</p>


<div class="main-layout">
 
   

 




<div class='page-title'>Validation belongs in a Model Object</div>

<div class='main-body'>
 
An application should perform data validation in a Model Object, where it can validate both 
user input, and the data being fetched from a database.  This validation should be performed in a 
<em>class</em>, and not in an .xml configuration file or some similar tool.

<P>The role of a Model Object is to implement business logic, and validation is the 
single most common (and arguably the most important) kind of business logic. <span class='highlight'>The fundamental 
reason for creating any class is often stated as bringing together data and closely related operations
on that data. This is often the first idea taught in courses on object programming.</span> 

<P>Surprisingly, there are many web presentation 
frameworks that do <em>not</em> follow this simple guiding principle of lasting value. Instead, they encourage the 
application programmer to <em>separate</em> data and logic, by doing validation either in 
Java Server Pages, or in configuration files (typically an <tt>.xml</tt> file). 
What is the justification for this? There does not seem to be any. 
If the reason is that "it allows validation to be configured", then this seems like a dubious argument.
Is it the job of a deployer or a page author to make decisions regarding important business logic?
No, it is not. On the contrary, for most organizations, allowing such casual changes to 
business logic in a production environment is regarded as highly undesirable, and is thus an argument 
<em>against</em> such techniques, not for them.

<P>Fundamentally, validation is a <em>programming</em> task, and it always will be : it involves <em>logic</em>. 
It is <em>not</em> a presentation task, and it is <em>not</em> a deployment task. Presentation frameworks
which provide validation tools are "leaking over" into the domain of business logic, in an 
apparent attempt to increase their list of features. However, this style is inappropriate for the  
application programmer, since it breaks a fundamental rule of object programming. 
Thus, such style of validation should likely be avoided. 

<P>Implementing validation in Model Objects is simple and natural. As usual, any common 
validations can be factored out into utility classes. In addition, writing test cases is simple, and 
can be executed stand-alone, outside of the web environment.

<P><b>Example</b>

<P>To assist the application programmer with common validations, the <a href="TopicAction5f31-2.html">WEB4J</a> tool defines a 
<a href="http://www.web4j.com/web4j/javadoc/hirondelle/web4j/model/Validator.html">Validator</a> interface, 
and a 
<a href="http://www.web4j.com/web4j/javadoc/hirondelle/web4j/model/Check.html">Check</a> 
class which returns some common implementations of that interface. Validation is implemented entirely in code, and never 
with JSPs or configuration files. Here, a <tt>Resto</tt> Model Object uses <tt>Check</tt> to perform 
all required validation in its constructor, by calling <tt>validateState</tt> :
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.fish.main.resto;

<span class='keyword'>import</span> hirondelle.web4j.model.ModelCtorException;
<span class='keyword'>import</span> hirondelle.web4j.model.ModelUtil;
<span class='keyword'>import</span> hirondelle.web4j.model.Id;
<span class='keyword'>import</span> hirondelle.web4j.security.SafeText;
<span class='keyword'>import</span> hirondelle.web4j.model.Decimal;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.web4j.model.Decimal.ZERO;
<span class='keyword'>import</span> hirondelle.web4j.model.Check;
<span class='keyword'>import</span> hirondelle.web4j.model.Validator;
<span class='keyword'>import</span> <span class='keyword'>static</span> hirondelle.web4j.util.Consts.FAILS;

<span class='comment'>/** Model Object for a Restaurant. */</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> Resto {

  <span class='comment'>/**
   Full constructor.
    
   @param aId underlying database internal identifier (optional) 1..50 characters
   @param aName of the restaurant (required), 2..50 characters
   @param aLocation street address of the restaurant (optional), 2..50 characters
   @param aPrice of the fish and chips meal (optional) $0.00..$100.00
   @param aComment on the restaurant in general (optional) 2..50 characters
  */</span>
  <span class='keyword'>public</span> Resto(
    Id aId, SafeText aName, SafeText aLocation, Decimal aPrice, SafeText aComment
  ) <span class='keyword'>throws</span> ModelCtorException {
    fId = aId;
    fName = aName;
    fLocation = aLocation;
    fPrice = aPrice;
    fComment = aComment;
    validateState();
  }
  
  <span class='keyword'>public</span> Id getId() { <span class='keyword'>return</span> fId; }
  <span class='keyword'>public</span> SafeText getName() {  <span class='keyword'>return</span> fName; }
  <span class='keyword'>public</span> SafeText getLocation() {  <span class='keyword'>return</span> fLocation;  }
  <span class='keyword'>public</span> Decimal getPrice() { <span class='keyword'>return</span> fPrice; }
  <span class='keyword'>public</span> SafeText getComment() {  <span class='keyword'>return</span> fComment; }

  <span class='keyword'>@Override</span> <span class='keyword'>public</span> String toString(){
    <span class='keyword'>return</span> ModelUtil.toStringFor(<span class='keyword'>this</span>);
  }
  
  <span class='keyword'>@Override</span> <span class='keyword'>public</span>  <span class='keyword'>boolean</span> equals(Object aThat){
    Boolean result = ModelUtil.quickEquals(<span class='keyword'>this</span>, aThat);
    <span class='keyword'>if</span> ( result ==  <span class='keyword'>null</span> ) {
      Resto that = (Resto) aThat;
      result = ModelUtil.equalsFor(
        <span class='keyword'>this</span>.getSignificantFields(), that.getSignificantFields()
      );
    }
    <span class='keyword'>return</span> result;
  }
  
  <span class='keyword'>@Override</span> <span class='keyword'>public</span> <span class='keyword'>int</span> hashCode(){
    <span class='keyword'>if</span> ( fHashCode == <span class='literal'>0</span> ){
      fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
    }
    <span class='keyword'>return</span> fHashCode;
  }
  
  <span class='comment'>// PRIVATE //
</span>  <span class='keyword'>private</span> <span class='keyword'>final</span> Id fId;
  <span class='keyword'>private</span> <span class='keyword'>final</span> SafeText fName;
  <span class='keyword'>private</span> <span class='keyword'>final</span> SafeText fLocation;
  <span class='keyword'>private</span> <span class='keyword'>final</span> Decimal fPrice;
  <span class='keyword'>private</span> <span class='keyword'>final</span> SafeText fComment;
  <span class='keyword'>private</span> <span class='keyword'>int</span> fHashCode;
  
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Decimal HUNDRED = Decimal.from(<span class='literal'>"100"</span>);

  <span class='keyword'>private</span> <span class='keyword'>void</span> validateState() <span class='keyword'>throws</span> ModelCtorException {
    ModelCtorException ex = <span class='keyword'>new</span> ModelCtorException();
    <span class='keyword'>if</span> ( FAILS == Check.optional(fId, Check.range(<span class='literal'>1</span>,<span class='literal'>50</span>)) ) {
      ex.add(<span class='literal'>"Id is optional, 1..50 chars."</span>);
    }
    <span class='keyword'>if</span> ( FAILS == Check.required(fName, Check.range(<span class='literal'>2</span>,<span class='literal'>50</span>)) ) {
      ex.add(<span class='literal'>"Restaurant Name is required, 2..50 chars."</span>);
    }
    <span class='keyword'>if</span> ( FAILS == Check.optional(fLocation, Check.range(<span class='literal'>2</span>,<span class='literal'>50</span>)) ) {
      ex.add(<span class='literal'>"Location is optional, 2..50 chars."</span>);
    }
    Validator[] priceChecks = {Check.range(ZERO, HUNDRED), Check.numDecimalsAlways(<span class='literal'>2</span>)};
    <span class='keyword'>if</span> ( FAILS == Check.optional(fPrice, priceChecks)) {
      ex.add(<span class='literal'>"Price is optional, 0.00 to 100.00."</span>);
    }
    <span class='keyword'>if</span> ( FAILS == Check.optional(fComment, Check.range(<span class='literal'>2</span>,<span class='literal'>50</span>))) {
      ex.add(<span class='literal'>"Comment is optional, 2..50 chars."</span>);
    }
    <span class='keyword'>if</span> ( ! ex.isEmpty() ) <span class='keyword'>throw</span> ex;
  }
  
  <span class='keyword'>private</span> Object[] getSignificantFields(){
    <span class='keyword'>return</span> <span class='keyword'>new</span> Object[] {fName, fLocation, fPrice, fComment};
  }
}
 
</PRE>
<br>
<br>
<br>

</div>




<div class='topic-section'>See Also :</div>
<div class='main-body'>
 
  
  <a href='TopicAction42fc-2.html?Id=112'>JSPs should contain only presentation logic</a> <br>
 
  
  <a href='TopicActiond08d-2.html?Id=187'>Model Objects</a> <br>
 
</div>


<div class='topic-section'>Would you use this technique?</div>
<div class='main-body'>
  
  <form action="http://www.javapractices.com/vote/AddVoteAction.do" method='post'>
    Yes<input type='radio' name='Choice' value='Y' >
    &nbsp;&nbsp;No<input type='radio' name='Choice' value='N'>
    &nbsp;&nbsp;Undecided<input type='radio' name='Choice' value="?" >
    &nbsp;&nbsp;<input type=submit value="Vote" >
    <input type='hidden' name='Operation' value='Apply'>
    <input type='hidden' name='TopicId' value='209'>
  </form>
</div>

<div style='height:10.0em;'></div>

 
 
</div>

  

 





<div align='center' class='legalese'>  
&copy; 2011 Hirondelle Systems |
<a href='../source/SourceAction-2.html'><b>Source Code</b></a><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |
<a href="mailto:webmaster@javapractices.com">Contact</a> |
<a href="http://creativecommons.org/licenses/by-nc-sa/1.0/">License</a> |
<a href='../apps/cjp.rss'>RSS</a>
<!-- ukey="2AC36CD2" -->
<!-- ckey="16DF3D87" -->
<br>

 Individual code snippets can be used under this <a href='../LICENSE.txt'>BSD license</a> - Last updated on June 6, 2010.<br>
 Over 150,000 unique IPs last month - <span title='Java Practices 2.6.5, Mon May 16 00:00:00 EDT 2011'>Built with</span> <a href='http://www.web4j.com/'>WEB4J</a>.<br>
 - In Memoriam : Bill Dirani -
</div>

<script src="../../www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2633428-1";
urchinTracker();
</script>



</body>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do;jsessionid=4FCCB481C702D708A7360133D128E359?Id=209 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:03 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
</html>
